/*
 * Copyright (C) 2010 ZXing authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.cloudwalk.libscan.decoding;

import android.graphics.Bitmap;
import android.graphics.ImageFormat;
import android.graphics.Rect;
import android.graphics.YuvImage;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;

import com.cloudwalk.libscan.BuildConfig;
import com.cloudwalk.libscan.camera.PlanarYUVLuminanceSource;
import com.cloudwalk.libscan.constant.ScanConstants;
import com.cloudwalk.libscan.manager.CloudScanManager;
import com.cloudwalk.libscan.utils.Nv21ImageUtil;
import com.cloudwalk.libscan.utils.TimerUtils;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.ReaderException;
import com.google.zxing.Result;
import com.google.zxing.common.HybridBinarizer;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Hashtable;


public final class DecodeHandler extends Handler {

    private static final String TAG = DecodeHandler.class.getSimpleName();

    private static final String DEAFAULT_FILE_PATH = Environment.getExternalStorageDirectory() + "/Download/";

    private final MultiFormatReader multiFormatReader;
    //        private final QRCodeReader mQrCodeReader;

    DecodeHandler(Hashtable<DecodeHintType, Object> hints) {
        multiFormatReader = new MultiFormatReader();
        multiFormatReader.setHints(hints);
//        mQrCodeReader = new QRCodeReader();
    }

    @Override
    public void handleMessage(Message message) {
        if (message.what == ScanConstants.DECODE) {
            decode((byte[]) message.obj, message.arg1, message.arg2);
        } else if (message.what == ScanConstants.PIC_DECODE) {
            decode((Bitmap) message.obj);
        } else if (message.what == ScanConstants.QUIT) {
            Looper.myLooper().quit();
        }
    }

    /**
     * 解析bitmap图片
     *
     * @param data
     * @return
     */
    public void decode(Bitmap data) {
        Result rawResult = null;
        RGBLuminanceSource source = new RGBLuminanceSource(data);
        BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
        long start = System.currentTimeMillis();
        try {
            rawResult = multiFormatReader.decodeWithState(bitmap);
        } catch (ReaderException re) {
        } finally {
            multiFormatReader.reset();
        }
        long end = System.currentTimeMillis();
        if (rawResult != null) {
            Log.d(TAG, "Found barcode (" + (end - start) + " ms):\n" + rawResult.toString());
//            Log.d(TAG, "识别成功图片的尺寸：" + "width = " + width + ", height = " + height);
//            FileUtils.createFileWithByte(data, "/Download/original_1");
//            FileUtils.createFileWithByte(i420Tonv21, "/Download/i420Tonv21_1");
//            FileUtils.createFileWithByte(rotatedData, "/Download/rotated_1");
            CloudScan.getInstance().handleDecode(rawResult);
        } else {
            Log.d(TAG, "Not Found barcode (" + (end - start) + " ms)");
            CloudScan.getInstance().handleDecode(null);

        }
    }

    /**
     * Decode the data within the viewfinder rectangle, and time how long it took. For efficiency,
     * reuse the same reader objects from one decode to the next.
     *
     * @param data   The YUV preview frame.
     * @param width  The width of the preview frame.
     * @param height The height of the preview frame.
     */
    private void decode(final byte[] data, int width, int height) {
        //Log.d(TAG, "decode: data = " + data.length);
        Result rawResult = null;
        byte[] i420Tonv21 = Nv21ImageUtil.i420ToNv21(data, width, height);
        //modify here
        byte[] rotatedData = Nv21ImageUtil.rotateYuv420Degree90(i420Tonv21, width, height);
        int tmp = width; // Here we are swapping, that's the difference to #11
        width = height;
        height = tmp;
        PlanarYUVLuminanceSource source = CloudScanManager.buildLuminanceSource(rotatedData, width, height);
        BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
        long start = System.currentTimeMillis();
        try {
            rawResult = multiFormatReader.decodeWithState(bitmap);
//            rawResult = mQrCodeReader.decode(bitmap, mHints);
        } catch (ReaderException re) {
        } finally {
            multiFormatReader.reset();
//            mQrCodeReader.reset();
        }
        if (rawResult != null) {
            long end = System.currentTimeMillis();
            Log.d(TAG, "Found barcode (" + (end - start) + " ms):\n" + rawResult.toString());
            savePic(rotatedData, "success/", width, height);
//            Log.d(TAG, "识别成功图片的尺寸：" + "width = " + width + ", height = " + height);
//            FileUtils.createFileWithByte(data, "/Download/original_1");
//            FileUtils.createFileWithByte(i420Tonv21, "/Download/i420Tonv21_1");
//            FileUtils.createFileWithByte(rotatedData, "/Download/rotated_1");
            CloudScan.getInstance().handleDecode(rawResult);
        } else {
            long end = System.currentTimeMillis();
            CloudScan.getInstance().setScanState(ScanConstants.DECODE_FAILED);
            //是否存图
            boolean isSavePic = TimerUtils.getInstance().isTimeUp(1000);
            if (isSavePic) {
                savePic(rotatedData, "failed/", width, height);
            }
        }
    }

    /**
     * 保存图片
     *
     * @param data
     * @param path
     */
    private void savePic(final byte[] data, String path, int width, int height) {
        if (BuildConfig.DEBUG) {//新增debug模式下可以开启.realese版本取消保存图片
            long temp = System.currentTimeMillis();
            SimpleDateFormat sf = new SimpleDateFormat("yyyyMMdd_HHmmss");
            String formatTime = sf.format(temp);
            if (data != null) {
                YuvImage yuvimage = new YuvImage(data, ImageFormat.NV21, width, height, null);//1920、1080分别是图的宽度与高度
                File file = makeFilePath(DEAFAULT_FILE_PATH + path, formatTime + ".jpg");
                FileOutputStream fos;
                try {
                    fos = new FileOutputStream(file);
                    yuvimage.compressToJpeg(new Rect(0, 0, width, height), 100, fos);//80--JPG图片的质量[0-100],100最高
                    fos.flush();
                    fos.close();
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 生成文件
     *
     * @param filePath
     * @param fileName
     * @return
     */
    private File makeFilePath(String filePath, String fileName) {
        File file = null;
        makeRootDirectory(filePath);
        try {
            file = new File(filePath + fileName);
            if (!file.exists()) {
                file.createNewFile();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return file;
    }

    /**
     * 生成文件夹
     *
     * @param filePath
     */
    private void makeRootDirectory(String filePath) {
        File file = null;
        try {
            file = new File(filePath);
            if (!file.exists()) {
                file.mkdir();
            }
        } catch (Exception e) {
            Log.i("error:", e + "");
        }
    }

}
